﻿using System;
using System.Collections.Generic;
using QuantumNet.Base.Interfaces;
using QuantumNet.Extensions;

namespace QuantumNet.Mathematics.Probability
{
    public class BinomialDistribution<T,A> : Interfaces.IDiscreteDistribution<T> where A:IReal<T>,new()
    {
        private static readonly A Wrapper = new A();

        public T P { get; set; }

        public T N { get; set; }

        public T Q { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:System.Object"/> class.
        /// </summary>
        public BinomialDistribution(T p, T n)
        {
            if(Wrapper.IsNotEqual(Wrapper.Modulo(n,2.CastTo<T>()),Wrapper.Zero()))
                return;
            if(Wrapper.IsGreatEqual(n,Minimum) || Wrapper.IsLessEqual(n,Maximum) && Wrapper.IsLessEqual(p,Wrapper.One()) || Wrapper.IsGreatEqual(p,Wrapper.Zero()))
            {
                P = p;
                N = n;
                Q = Wrapper.Subtract(Wrapper.One(), p);
            }
            
        }

        public T Mode
        {
            get { throw new NotImplementedException(); }
        }

        public T Maximum
        {
            get { throw new NotImplementedException(); }
        }

        public T Minimum
        {
            get { throw new NotImplementedException(); }
        }

        public T Median
        {
            get { throw new NotImplementedException(); }
        }

        public T Probability(T x)
        {
            throw new NotImplementedException();
        }

        public T Variance
        {
            get { return Wrapper.Prod(new List<T> {N, P, Q}); }
        }

        public T Sigma
        {
            get { return Wrapper.Sqrt(Variance); }
        }

        public T Entropy
        {
            // TODO Changer la variable E
            get
            {
                return Wrapper.Multiply(0.5.CastTo<T>(),
                                        Wrapper.Ln(
                                            Wrapper.Prod(new List<T>
                                                             {2.CastTo<T>(), Wrapper.Pi, N, 2.71.CastTo<T>(), P, Q})));
            }
        }

        public T Skewness
        {
            get { return Wrapper.Divide(Wrapper.Subtract(Wrapper.One(), Wrapper.Multiply(2.CastTo<T>(), P)), Variance); }
        }

        public T UnnormalizedKurtosis
        {
            get { throw new NotImplementedException(); }
        }

        public T NormalizedKurtosis
        {
            get { throw new NotImplementedException(); }
        }

        public T Esperance
        {
            get { return Wrapper.Multiply(N, P); }
        }

        public T CumulativeDistribution(T x)
        {
            throw new NotImplementedException();
        }
    }

}
